package dd.lo.chapter6;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 对应练习示例
 * Draw one example of every shape and line that OpenCV can draw.
 */
public class Example1 extends Application {
    private ImageView imageView;

    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        int w = 1000, h = 150;
        imageView = new ImageView();
        imageView.setFitWidth(w);
        imageView.setFitHeight(h);
        //imageView放到一个pane的中间
        BorderPane root = new BorderPane();
        root.setCenter(imageView);
        Scene scene = new Scene(root, w, h);
        scene.setOnKeyReleased(keyEvent -> {
            //按下esc可以关闭程序
            if (KeyCode.ESCAPE == keyEvent.getCode()) {
                stage.close();
            }
        });
        stage.setScene(scene);
        stage.setTitle("C6E1-Drawing shapes via OpenCV");
        stage.setResizable(false);
        asyncDraw(w, h);
        stage.show();
    }

    private void asyncDraw(int w, int h) {
        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                long startTime = new Date().getTime();
                //创建一张图片，8bit，3通道
                Mat bg = new Mat(h, w, CvType.CV_8UC3);
                //使用最简单的setTo功能，将每个点设置成白色（BGR）
                bg.setTo(new Scalar(255, 255, 255));
                //画圆的圆心，蓝色，抗锯齿边，注意中文的文字显示不了，因为没有对应字体
                Imgproc.putText(bg, "Circle", new Point(0, 20), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(0, 0, 0), 1, Imgproc.LINE_8);
                Imgproc.circle(bg, new Point(50, 50), 45, new Scalar(new double[]{255, 0, 0}), 2, Imgproc.LINE_AA);
                //画直线
                Imgproc.putText(bg, "Line&Polyline", new Point(100, 20), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(0, 0, 0), 1, Imgproc.LINE_8);
                Point p1 = new Point(105, 5), p2 = new Point(165, 85);
                Imgproc.line(bg, p1, p2, new Scalar(new double[]{0, 0, 0}), 2, Imgproc.LINE_AA);
                System.out.println("Line clip result: " + Imgproc.clipLine(new Rect(55, 10, 1, 100), p1, p2));
                //画多线非填充图形，可以一次画多条线，一个MatOfPoint是一条线
                List<MatOfPoint> points1 = new ArrayList<>();
                points1.add(new MatOfPoint(new Point(125, 5), new Point(155, 25), new Point(165, 65)));
                Imgproc.polylines(bg, points1, false,  new Scalar(new double[]{0, 0, 0}), 2, Imgproc.LINE_AA);
                //画矩形，左上角点和宽高
                Imgproc.putText(bg, "Rectangle", new Point(200, 20), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(0, 0, 0), 1, Imgproc.LINE_8);
                Imgproc.rectangle(bg, new Rect(220, 5, 76, 95), new Scalar(new double[]{0, 255, 0}));
                //画多线填充图形
                Imgproc.putText(bg, "Fillpoly", new Point(300, 20), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(0, 0, 0), 1, Imgproc.LINE_8);
                List<MatOfPoint> points2 = new ArrayList<>();
                points2.add(new MatOfPoint(new Point(325, 5), new Point(355, 25), new Point(365, 65)));
                Imgproc.fillPoly(bg, points2,  new Scalar(new double[]{0, 0, 0}), Imgproc.LINE_AA);
                //画椭圆线，可以通过控制开始角度和结束角度控制椭圆线的部分，所有旋转的角度都是，正数是顺时针方向计算的角度，负数是逆时针方向的角度
                Imgproc.putText(bg, "Ecllipse", new Point(400, 20), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(0, 0, 0), 1, Imgproc.LINE_8);
                Imgproc.ellipse(bg, new Point(450, 50), new Size(65, 25), -30, 30, 210, new Scalar(new double[]{0, 0, 255}), 2);
                MatOfByte buffer = new MatOfByte();
                Imgcodecs.imencode(".jpeg", bg, buffer);
                Platform.runLater(() -> imageView.setImage(new Image(new ByteArrayInputStream(buffer.toArray()))));
                System.out.printf("Drawing time consume: %d ms.\n", new Date().getTime() - startTime);
                return null;
            }
        };
        new Thread(task).start();
    }
}
